#include "audio_decoder.h"
#include "esp_audio_dec.h"
#include "esp_audio_dec_default.h"
#include "esp_audio_dec_reg.h"
#include <esp_heap_caps.h>
#include <stdlib.h>
#include <string.h>
#include <esp_err.h>
#include <bsp_config.h>
#include <esp_log.h>

#define TAG "[AUDIO_PROCESSOR] Deocder"

struct audio_decoder
{
    esp_audio_dec_handle_t decoder;
    bool is_running;

    RingbufHandle_t input_buf;
    RingbufHandle_t output_buf;
};

static void audio_decoder_task(void *arg)
{
    ESP_LOGI(TAG, "Decoder task created");
    audio_decoder_t *audio_decoder = (audio_decoder_t *)arg;
    uint8_t *read_buf = NULL;
    size_t read_size = 0;

    esp_audio_dec_in_raw_t in_frame = {0};

    uint32_t out_len = BSP_CODEC_BIT_PER_SAMPLE * BSP_CODEC_CHANNEL_COUNT * BSP_CODEC_SAMPLE_RATE / 8 / 1000 * 60;
    esp_audio_dec_out_frame_t out_frame = {
        .buffer = heap_caps_malloc(out_len, MALLOC_CAP_SPIRAM),
        .len = out_len,
    };

    while (audio_decoder->is_running)
    {
        // 读取环形缓存
        read_buf = xRingbufferReceive(audio_decoder->input_buf, &read_size, portMAX_DELAY);
        assert(read_buf);
        in_frame.buffer = read_buf;
        in_frame.len = read_size;
        while (in_frame.len > 0)
        {
            // 解码
            int ret = esp_audio_dec_process(audio_decoder->decoder, &in_frame, &out_frame);
            if (ret == ESP_AUDIO_ERR_BUFF_NOT_ENOUGH)
            {
                ESP_LOGE(TAG, "Decoder buffer not enough; needed %lu, current %lu", out_frame.needed_size, out_frame.len);
                abort();
            }
            ESP_ERROR_CHECK(ret);

            // 写到输出缓存
            ESP_LOGD(TAG, "Decoded %lu bytes", out_frame.decoded_size);
            assert(xRingbufferSend(audio_decoder->output_buf, out_frame.buffer, out_frame.decoded_size, portMAX_DELAY) == pdTRUE);

            in_frame.buffer += in_frame.consumed;
            in_frame.len -= in_frame.consumed;
        }

        vRingbufferReturnItem(audio_decoder->input_buf, read_buf);
    }
}

audio_decoder_t *audio_decoder_create(void)
{
    audio_decoder_t *audio_decoder = (audio_decoder_t *)malloc(sizeof(audio_decoder_t));
    assert(audio_decoder);
    memset(audio_decoder, 0, sizeof(audio_decoder_t));
    // docoder初始化

    // 注册解码器
    ESP_ERROR_CHECK(esp_opus_dec_register());

    esp_opus_dec_cfg_t opus_dec_cfg = {
        .channel = BSP_CODEC_CHANNEL_COUNT,
        .sample_rate = BSP_CODEC_SAMPLE_RATE,
        // .frame_duration = ESP_OPUS_DEC_FRAME_DURATION_60_MS,
        .self_delimited = false,
    };

    esp_audio_dec_cfg_t dec_cfg = {
        .cfg = &opus_dec_cfg,
        .cfg_sz = sizeof(esp_opus_dec_cfg_t),
        .type = ESP_AUDIO_TYPE_OPUS,
    };

    ESP_ERROR_CHECK(esp_audio_dec_open(&dec_cfg, &audio_decoder->decoder));

    return audio_decoder;
}

void audio_decoder_start(audio_decoder_t *audio_decoder)
{
    assert(audio_decoder);
    audio_decoder->is_running = true;
    assert(xTaskCreatePinnedToCoreWithCaps(audio_decoder_task, "dec_task", 1024 * 32, audio_decoder, 5, NULL, 1, MALLOC_CAP_SPIRAM) == pdTRUE);
}

void audio_decoder_set_input_buffer(audio_decoder_t *audio_decoder, RingbufHandle_t buf)
{
    assert(audio_decoder);
    assert(buf);
    audio_decoder->input_buf = buf;
}

void audio_decoder_set_output_buffer(audio_decoder_t *audio_decoder, RingbufHandle_t buf)
{
    assert(audio_decoder);
    assert(buf);
    audio_decoder->output_buf = buf;
}
